package com.zeng.springcloud.config;

import org.springframework.boot.env.PropertiesPropertySourceLoader;
import org.springframework.boot.env.PropertySourceLoader;
import org.springframework.boot.env.YamlPropertySourceLoader;
import org.springframework.cloud.bootstrap.config.PropertySourceLocator;
import org.springframework.core.env.CompositePropertySource;
import org.springframework.core.env.Environment;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;

import java.io.IOException;
import java.nio.file.*;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY;

/**
 * @author zyb
 * @date 2021-05-30 16:41
 */
public class ConfigDefaultPropertySourceLocator implements PropertySourceLocator {

    private static final List<String> FILE_EXTENSIONS = Arrays.asList(".properties", "yml", "yaml");
    private static final String RESOURCE_PATH = "META-INF/config/";
    private static final String FILE_NAME = "default";

    private final ResourceLoader resourceLoader;
    private final List<PropertySourceLoader> propertySourceLoaders;
    private final WatchService watchService;
    private final ExecutorService executorService;

    public ConfigDefaultPropertySourceLocator() {
        this.propertySourceLoaders = new LinkedList<>();
        propertySourceLoaders.add(new PropertiesPropertySourceLoader());
        propertySourceLoaders.add(new YamlPropertySourceLoader());
        this.resourceLoader = new DefaultResourceLoader();
        this.watchService = FileSystems.getDefault().newWatchService();
        this.executorService = Executors.newFixedThreadPool(2);
        executorService.execute(()->{
            while (true){
                WatchKey watchKey = watchService.take();
                for (WatchEvent<?> pollEvent : watchKey.pollEvents()) {
                    Path path = (Path) pollEvent.context();

                }
            }
        });
    }


    @Override
    public PropertySource<?> locate(Environment environment) {
        CompositePropertySource propertySource = new CompositePropertySource("config-default");
        List<Resource> resources = loadResources();
        for (PropertySourceLoader propertySourceLoader : propertySourceLoaders) {
            for (Resource resource : resources) {
                if (!resource.exists()) {
                    continue;
                }
                registerWatchFile(resource);
                List<PropertySource<?>> propertySources;
                try {
                    propertySources = propertySourceLoader.load(FILE_NAME, resource);
                    propertySources.forEach(propertySource::addPropertySource);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }


        return propertySource;
    }

    private void registerWatchFile(Resource resource) {
        Path path = resource.getFile().toPath();
        path.register(watchService, ENTRY_MODIFY);

    }

    private List<Resource> loadResources() {
        return FILE_EXTENSIONS.stream()
                .map(fileExtension -> resourceLoader.getResource(RESOURCE_PATH + FILE_NAME + fileExtension))
                .collect(Collectors.toList());
    }


}